import dayjs from "dayjs";
import { ObjectId, Filter } from "mongodb";

import * as db from "../db";
import * as crypto from "../libs/crypto";
import { stats } from "../libs/stats";
import { ISession, IUser, UserStatus } from "../models/user";

import * as sessionService from "./session.service";

// 用户注册
export async function register(record: IUser) {
  // 检查账号是否冲突
  const user = await db.users.findOne({
    account: record.account,
  });
  if (user) throw stats.ErrUserAccountExist;
  // 检查昵称是否冲突
  const user2 = await db.users.findOne({
    nickname: record.nickname,
  });
  if (user2) throw stats.ErrUserNicknameExist;
  // 密码加密存储
  record.salt = crypto.getRandomStr();
  record.password = crypto.sha1Crypto(record.password, record.salt);
  // 加入时间和状态
  record.createdAt = dayjs().unix();
  record.status = 1;
  // 插入数据库
  const result = await db.users.insertOne(record);
  return result.insertedId;
}

// 用户登陆
export async function login(record: IUser) {
  // 根据传入的account判断用户是否存在
  const user = await db.users.findOne({
    account: record.account,
  });
  if (!user) throw stats.ErrUserNotFound;
  // 判断用户是否禁用
  if (user.status === UserStatus.Disabled) throw stats.ErrUserAccountDisable;
  // 获取加salt之后的密码与数据库的密码进行比对
  const pwd = crypto.sha1Crypto(record.password, user.salt);
  if (pwd !== user.password) throw stats.ErrPasswordIncorrect;
  // 生成session保存到数据库中
  const session: ISession = {
    sid: crypto.getRandomStr(),
    userId: user._id,
    ip: "0.0.0.0",
    createdAt: new Date(),
  };
  await sessionService.createSession(session);
  // 返回session的id
  return session.sid;
}

export async function logout(token: string) {
  // 删除当前session_id对应的session记录
  await sessionService.deleteSession(token);
}

// 获得用户信息(所有信息)
export async function getAllUserInfo(sid: string) {
  // 查找session
  const session = await sessionService.findSession(sid);
  // 根据session查找用户
  const user = await db.users.findOne({
    _id: new ObjectId(session.userId),
  });
  if (!user) throw stats.ErrUserNotFound;
  return user;
}

// 获得用户信息(不包括密码、salt)
export async function getUserInfo(sid: string) {
  // 查找session
  const session = await sessionService.findSession(sid);
  // 根据session查找用户(使用projection返回部分信息)
  const user = await db.users.findOne(
    {
      _id: new ObjectId(session.userId),
    },
    {
      projection: {
        _id: 1,
        account: 1,
        nickname: 1,
        status: 1,
        createdAt: 1,
      },
    }
  );
  if (!user) throw stats.ErrUserNotFound;
  return user;
}

// 修改密码
export async function changePwd(
  token: string,
  oldPwd: string,
  password: string,
  confirmPwd: string
) {
  // 根据token获取所有用户信息
  const user = await getAllUserInfo(token);
  // 先验证旧密码是否正确
  const pwd = crypto.sha1Crypto(oldPwd, user.salt);
  if (pwd !== user.password) throw stats.ErrOldPasswordIncorrect;
  // 两次密码输入不一致的情况
  if (password !== confirmPwd) throw stats.ErrPasswordNotUniform;
  // 用新密码更新数据库的salt和password
  user.salt = crypto.getRandomStr();
  user.password = crypto.sha1Crypto(password, user.salt);
  await db.users.updateOne(
    {
      _id: user._id,
    },
    {
      $set: user,
    }
  );
  // 修改密码之后清除该用户的所有session
  sessionService.deleteAll(user._id);
}
